home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 November: Tool Chest / Dev.CD Nov 98 TC.toast / Sample Code / Snippets / Toolbox / ReKeyTrans / Source / ReKeyTrans.c
Encoding:
C/C++ Source or Header  |  1996-09-17  |  7.2 KB  |  261 lines  |  [TEXT/CWIE]

  1. /*******************************************************************************
  2.  
  3.     OpenWindow by Cameron
  4.  
  5.     (OpenWindow? Cameron? What's going on here?)
  6.  
  7.     OK, intrepid developer-like objects, we admit it! We don't
  8.     know where this sample came from and we don't know anything about
  9.     its original intent. However, since we're super-geniuses, we were
  10.     able to make up a plausible story.
  11.  
  12.     Say you're a terminal emulator. And you have to run on a Mac Plus.
  13.     With us so far? Now, the Plus doesn't have a control key, but you'd
  14.     really like to pretend it does. So you use the option key. Here's where
  15.     the problem comes in.
  16.  
  17.     The default behavior of KeyTrans is to support umlauts and other
  18.     fun letter modifiers by making option-U, for example, into a
  19.     "dead" key which results in no keystrokes but modifies subsequent
  20.     keystrokes. So when you type option-U followed by a u, you get: 'ΓΌ'.
  21.     And there was much rejoicing, except in Terminal Emulator Land.
  22.     There, the people were downtrodden, as they had no way to tell
  23.     their UNIX command line to clear.
  24.  
  25.     So, you ask, why don't I just install my own keymap? Well, that'd
  26.     be swell for all us qwerty people, but the people who type on those
  27.     keyboards with all the keys rearranged would really hate it (Hi Quinn!)
  28.     and they'd have to relearn the icky qwerty (try typing that 5 times
  29.     fast) layout again after they'd gone to all the effort of rearranging
  30.     their keycaps on the keyboard so they'd feel funny (they're not all
  31.     the same shape, you know). So...
  32.     
  33.     This sample shows how to patch KeyTrans in order to completely
  34.     ignore the dead-key processing that goes on and lets you type those
  35.     fancy accented characters. You're back in 7-bit ASCII days now,
  36.     bucko. Enjoy.
  37.  
  38. *******************************************************************************/
  39.  
  40. #include <String.h>
  41.  
  42. /* Type 1 includes */
  43. #include <Types.h>
  44. #include <QuickDraw.h>
  45.  
  46. /* Type 2 includes */
  47. #include <Controls.h>
  48. #include <Events.h>
  49. #include <Fonts.h>
  50. #include <Memory.h>
  51. #include <Menus.h>
  52. #include <OSUtils.h>
  53. #include <Resources.h>
  54. #include <SegLoad.h>
  55. #include <TextEdit.h>
  56. #include <ToolUtils.h>
  57. #include <Traps.h>
  58. #include <Script.h>
  59.  
  60. /* Type 3 includes */
  61. #include <Desk.h>
  62. #include <Files.h>
  63. #include <OSEvents.h>
  64. #include <Windows.h>
  65.  
  66. /* Type 4 includes */
  67. #include <Dialogs.h>
  68.  
  69. /* Type BITE ME includes */
  70.  
  71. #include <Traps.h>
  72. #include <Assembler.h>
  73.  
  74. /*  Global Variables  */
  75.  
  76. Str255            WindTitle;
  77. WindowPtr        MyWindow,aWindPtr;
  78. short            err,keycode,StartV,StartH;
  79. EventRecord        MyEvent;
  80. Boolean            quit,DrawOn;
  81. Rect            WindRect,Rect1,Rect2;
  82. Point            aPoint,lastPoint;
  83. long            KCHRID,newKey,state;
  84. Handle            KCHRHdl;
  85.  
  86. /*************************************************************************************/
  87.  
  88. static asm pascal UniversalProcPtr KeyTransPatcher (UniversalProcPtr)
  89. {
  90.     // compute patch code size
  91.  
  92.     LEA        endPatch,A1
  93.     LEA        patch,A0
  94.     MOVE.L    A1,D0
  95.     SUB.L    A0,D0
  96.  
  97.     MOVE.L    D0,-(A7)                // save size for later
  98.     _NewPtrSys                        // alloc block in sys heap for patch
  99.     MOVE.L    (A7)+,D0                // restore size for BlockMove
  100.     MOVE.L    A0,D1                    // set up CCR (I thought 68K was CISC!)
  101.     BEQ.S    fail                    // if'n (_NewPtrSys) didn't work, give up
  102.     MOVE.L    A0,A1                    // new block is BlockMove dest
  103.  
  104.     // hijack A0 temporarily, thank you
  105.  
  106.     LEA        oldTrapAddress,A0        // point to PC-relative storage
  107.     MOVE.L    4(A7),(A0)                // set PC-relative storage
  108.  
  109.     LEA        patch,A0                // source for BlockMove
  110.     _BlockMove                        // copy patch to system heap
  111.     BRA.S    out                        // skip exception handling
  112. fail:
  113.     SUB.L    A1,A1                    // tell caller we're hosed
  114. out:
  115.     MOVE.L    (A7)+,A0                // get return address
  116.     ADDQ.L    #4,A7                    // drop arg
  117.     MOVE.L    A1,(A7)                    // set return value
  118.     JMP        (A0)                    // phone home
  119.  
  120. patch:
  121.     // set the up/down bit - KeyTrans won't process
  122.     // "dead" up strokes. Currently, this does not
  123.     // affect the event record up/down state.
  124.  
  125.     BSET    #7,9(SP)
  126.     MOVE.L    oldTrapAddress,-(A7)
  127.     RTS
  128. oldTrapAddress:
  129.     DC.L    'hack'
  130. endPatch:
  131. }
  132.  
  133. /*************************************************************************************/
  134. static void    InitMac(void)
  135. {
  136.     InitGraf(&qd.thePort);
  137.     InitFonts();
  138.     FlushEvents(everyEvent,0);
  139.     InitWindows();
  140.     InitCursor();
  141.     quit = false;
  142.     DrawOn = false;
  143.     StartV = 25;
  144.     StartH = 5;
  145. }
  146. /*************************************************************************************/
  147. static void    DoCR(void)
  148. {
  149.     if (lastPoint.v > (*MyWindow).portRect.bottom-15)
  150.     {
  151.         EraseRect(&(*MyWindow).portRect);
  152.         lastPoint.v = StartV;
  153.         lastPoint.h = StartH;
  154.     }
  155.     else
  156.     {
  157.         lastPoint.v = lastPoint.v+14;
  158.         lastPoint.h = StartH;
  159.     }
  160. }
  161.  
  162. /*************************************************************************************/
  163. static void    DoKeyDown(void)
  164. {
  165.     if (BitAnd(MyEvent.message,charCodeMask) == 'q'        // if the user typed the magic "cmd-q" sequence,
  166.     && BitAnd(MyEvent.modifiers,0x0100))
  167.         { quit = true; }                                // it's Miller time!
  168.     else    {
  169.         MoveTo(lastPoint.h,lastPoint.v);
  170.         newKey = BitAnd(MyEvent.message,keyCodeMask);    // Strip out all but the keycode
  171.         newKey = BitShift(newKey,-8);                    // move the keycode down to the low byte
  172.         keycode = LoWord(newKey);                        // extract the low word of the event message (ignore modifier bits)
  173.         keycode = keycode & 0xFF7F;                        // make sure it looks like a key down stroke
  174.         newKey = KeyTranslate(*KCHRHdl, keycode, (UInt32*)&state);    // have KeyTrans translate the key code to ASCII
  175.         keycode = LoWord(newKey);                        // now get the ASCII 2 value (IM5, p195 has it backward!)
  176.         DrawChar(keycode);                                // just to make sure, let's have a look
  177.         GetPen(&lastPoint);                                // now make sure we stay inside the content region
  178.         if (lastPoint.h > ((*MyWindow).portRect.right-10))    // if we're getting to close to the edge,
  179.             {     DoCR();    }                                // go fix it up
  180.     }
  181. }
  182. /*************************************************************************************/
  183. void main()
  184. {
  185.     InitMac();
  186.     
  187.     MyWindow = GetNewWindow(2009,nil,(WindowPtr)-1);
  188.  
  189.     if (MyWindow)
  190.     {
  191.         SetPort(MyWindow);
  192.         MoveTo(StartH,StartV);
  193.         lastPoint.h = StartH;
  194.         lastPoint.v = StartV;
  195.         KCHRID = GetScriptVariable(smRoman, smScriptKeys);    /* returns resource ID of KCHR being used by system */
  196.         KCHRHdl = GetResource('KCHR',KCHRID);
  197.         if (KCHRHdl)
  198.         {
  199.             UniversalProcPtr    oldKeyTrans = GetToolTrapAddress (_KeyTrans),
  200.                                 newKeyTrans = KeyTransPatcher (oldKeyTrans);
  201.  
  202.             if (newKeyTrans)
  203.             {
  204.                 SetToolTrapAddress (newKeyTrans, _KeyTrans);
  205.  
  206.                 MoveHHi(KCHRHdl);
  207.                 HLock(KCHRHdl);
  208.  
  209.                 while (quit != true)
  210.                 {
  211.                     if (DrawOn)
  212.                     {
  213.                         if (StillDown())
  214.                         {
  215.                             GetMouse(&aPoint);
  216.                             StdLine(aPoint);
  217.                         }
  218.                         else { DrawOn = false; }
  219.                     }
  220.                     else
  221.                     {
  222.                         if (WaitNextEvent(everyEvent,&MyEvent,0,nil))
  223.                         {
  224.                             switch (MyEvent.what)
  225.                             {
  226.                                 case mouseDown:
  227.                                 {
  228.                                     Rect boundsRect = qd.screenBits.bounds;
  229.  
  230.                                     switch (FindWindow(MyEvent.where,&aWindPtr))
  231.                                     {
  232.                                         case inGoAway :
  233.                                             quit = TrackGoAway (aWindPtr,MyEvent.where);
  234.                                             break;
  235.                                         case inDrag :
  236.                                             InsetRect (&boundsRect,4,4);
  237.                                             DragWindow (aWindPtr,MyEvent.where,&boundsRect);
  238.                                             break;                                            
  239.                                     }
  240.                                     break;
  241.                                 }
  242.                                 case keyDown:
  243.                                 {
  244.                                     DoKeyDown();
  245.                                     break;
  246.                                 }
  247.                                 case autoKey:
  248.                                 {
  249.                                     DoKeyDown();
  250.                                     break;
  251.                                 }
  252.                             }
  253.                         }
  254.                     }
  255.                 }
  256.                 SetToolTrapAddress (oldKeyTrans, _KeyTrans);
  257.                 DisposePtr ((Ptr) newKeyTrans);
  258.             }
  259.         }
  260.     }
  261. }